#!/usr/bin/perl

# $Id$

######################################################################
package Swignition::GenericParser::HTTP;
######################################################################

use Swignition::MagicString;
use Swignition::uF;
use DateTime;
use URI::URL;
use XML::LibXML qw(:all);
use strict;


sub is_enabled
{
	my $this = shift;
	
	return 1
		if ($this->{options}->{p_http} && $this->{RESPONSE});
		
	return 0;
}


sub consume
{
	my $this = shift;
	return unless ($this->{RESPONSE});
	my $nsrdf   = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
	my $nshttp  = 'http://www.w3.org/2006/http#';
	my $nshttpH = 'http://www.w3.org/2008/http-headers#';
	my $nshttpM = 'http://www.w3.org/2008/http-methods#';
	my $nshttpS = 'http://www.w3.org/2008/http-statusCodes#';
	my $rdftype = $nsrdf.'type';

	my $Request = Swignition::DataModel::BlankNode->new($this->model);
	my $t = $this->graph('HTTP')->quick_rrr($Request, $rdftype, $nshttp.'Request');
	$this->graph->add_triple($t);
	
	my $RequestH = Swignition::DataModel::Collection->new($this->model, 'List');
	$t = $this->graph('HTTP')->quick_rrr($Request, $nshttp.'headers', $RequestH);
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrr($this->uri, 'http://buzzword.org.uk/rdf/http-ext#related-request', $Request);
	$this->graph->add_triple($t);

	my $Response = Swignition::DataModel::BlankNode->new($this->model);
	my $t = $this->graph('HTTP')->quick_rrr($Response, $rdftype, $nshttp.'Response');
	$this->graph->add_triple($t);
	
	my $ResponseH = Swignition::DataModel::Collection->new($this->model, 'List');
	$t = $this->graph('HTTP')->quick_rrr($Response, $nshttp.'headers', $ResponseH);
	$this->graph->add_triple($t);
	
	$t = $this->graph('HTTP')->quick_rrr($Request, $nshttp.'response', $Response);
	$this->graph->add_triple($t);
	
	foreach my $header ( $this->{REQUEST}->headers->header_field_names )
	{
		my @h = $this->{REQUEST}->header($header);
		foreach my $h (@h)
		{
			my $hnode = consume_header($this, $header, $h);
			$RequestH->add_node($hnode)
		}
	}
	
	my $rproto = $this->{REQUEST}->protocol;
	$rproto =~ s|^HTTP/||;
	
	if ($rproto)
	{
		$t = $this->graph('HTTP')->quick_rrl($Request, $nshttp.'httpVersion', $rproto, 'http://www.w3.org/2001/XMLSchema#decimal');
		$this->graph->add_triple($t);
	}
	
	$t = $this->graph('HTTP')->quick_rrr($Request, $nshttp.'method', $nshttpM.uc($this->{REQUEST}->method));
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrl($Request, $nshttp.'methodName', $this->{REQUEST}->method);
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrl($Request, $nshttp.'absoluteURI', $this->{REQUEST}->uri, 'http://www.w3.org/2001/XMLSchema#anyURI');
	$this->graph->add_triple($t);

	foreach my $header ( $this->{RESPONSE}->headers->header_field_names )
	{
		my @h = $this->{RESPONSE}->header($header);
		foreach my $h (@h)
		{
			my $hnode = consume_header($this, $header, $h);
			$ResponseH->add_node($hnode)
		}
	}
	
	my $rdate = DateTime->from_epoch( epoch => $this->{RESPONSE}->headers->date);
	$rproto = $this->{RESPONSE}->protocol;
	$rproto =~ s|^HTTP/||;
	
	if ($rproto)
	{
		$t = $this->graph('HTTP')->quick_rrl($Response, $nshttp.'httpVersion', $rproto, 'http://www.w3.org/2001/XMLSchema#decimal');
		$this->graph->add_triple($t);
	}

	$t = $this->graph('HTTP')->quick_rrr($Response, $nshttp.'statusCode', $nshttpS.'statusCode'.$this->{RESPONSE}->code);
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrl($Response, $nshttp.'statusCodeNumber', $this->{RESPONSE}->code, 'http://www.w3.org/2001/XMLSchema#integer');
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrl($Response, $nshttp.'reasonPhrase', $this->{RESPONSE}->message, 'http://www.w3.org/2001/XMLSchema#string');
	$this->graph->add_triple($t);

	$t = $this->graph('HTTP')->quick_rrl($Response, $nshttp.'http://purl.org/dc/terms/date', $rdate);
	$this->graph->add_triple($t);

	$this->mergeNS('ianalink',
		'http://www.iana.org/assignments/relation/',
		'IANA Registered Link Types',
		-1,
		0);
	$this->mergeNS('ht',
		$nshttp,
		'HTTP Vocabulary in RDF',
		-1,
		0);
	$this->mergeNS('htx',
		'http://buzzword.org.uk/rdf/http-ext#',
		'HTTP Vocabulary in RDF Extentions',
		-1,
		0);
	$this->mergeNS('hth',
		$nshttpH,
		'HTTP Vocabulary in RDF (Headers)',
		-1,
		0);
	$this->mergeNS('htm',
		$nshttpM,
		'HTTP Vocabulary in RDF (Methods)',
		-1,
		0);
	$this->mergeNS('hts',
		$nshttpS,
		'HTTP Vocabulary in RDF (Status Codes)',
		-1,
		0);
}

sub relationship
{
	my $str   = shift;

	if ($str =~ /^([a-z][a-z0-9\+\.\-]*)\:/i)
	{
		# seems to be an absolute URI, so can safely return "as is".
		return $str;
	}

	return 'http://www.iana.org/assignments/relation/'.lc($str);

	my $url = url lc($str), 'http://www.iana.org/assignments/relation/';
	return $url->abs->as_string;

	return undef;
}

sub consume_header
{
	my $nsrdf   = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
	my $nshttp  = 'http://www.w3.org/2006/http#';
	my $nshttpH = 'http://www.w3.org/2008/http-headers#';
	my $nshttpM = 'http://www.w3.org/2008/http-methods#';
	my $nshttpS = 'http://www.w3.org/2008/http-statusCodes#';
	my $rdftype = $nsrdf.'type';

	my $this    = shift;
	my $header  = shift;
	my $value   = shift;
	my $gname   = shift || 'HTTP';
	
	my $Header = Swignition::DataModel::BlankNode->new($this->model);
	my $t = $this->graph($gname)->quick_rrr($Header, $rdftype, $nshttp.'MessageHeader');
	$this->graph->add_triple($t);

	$t = $this->graph($gname)->quick_rrl($Header, $nshttp.'fieldName', $header);
	$this->graph->add_triple($t);

	$t = $this->graph($gname)->quick_rrr($Header, $nshttp.'headerName', $nshttpH.lc($header));
	$this->graph->add_triple($t);

	$t = $this->graph($gname)->quick_rrl($Header, $nshttp.'fieldValue', $value);
	$this->graph->add_triple($t);

	if ($header =~ /content-length/i)
	{
		$t->object->set_datatype('http://www.w3.org/2001/XMLSchema#nonNegitiveInteger');
	}
	elsif ($header =~ /(\bdate$)|(^last-modified$)|(^if-modified-since$)/i)
	{
		my $dt   = Swignition::uF::datetime($value);
		$t = $this->graph($gname)->quick_rrl($Header, $nshttp.'fieldValue', $dt);
		$this->graph->add_triple($t);
	}
	elsif ($header =~ /link/i)
	{
		my $h2 = $value;
		my $uri = undef;
		if ($h2 =~ /^(\s*<([^>]*)>\s*)/)
		{
			$uri = $2;
			$h2  = substr($value, length($1));
		}
		else
		{
			next;
		}
		
		my $ParamList     = Swignition::DataModel::Collection->new($this->model, 'List');

		my $HeaderElement = Swignition::DataModel::BlankNode->new($this->model);
		my $t = $this->graph($gname)->quick_rrr($HeaderElement, $rdftype, $nshttp.'HeaderElement');
		$this->graph->add_triple($t);
		
		$t = $this->graph($gname)->quick_rrl($HeaderElement, $nshttp.'elementName', $uri);
		$this->graph->add_triple($t);

		$t = $this->graph($gname)->quick_rrr($HeaderElement, $nshttp.'params', $ParamList);
		$this->graph->add_triple($t);

		my $HeaderElementList = Swignition::DataModel::Collection->new($this->model, 'List');
		$HeaderElementList->add_node($HeaderElement);

		$t = $this->graph($gname)->quick_rrr($Header, $nshttp.'headerElements', $HeaderElementList);
		$this->graph->add_triple($t);
				
		$uri = $this->uri($uri);
		while ($h2 =~ /^(\s*\;\s*(\/|[a-z0-9-]+)\s*\=\s*("[^"]*"|'[^']*'|[^\s\'\"\;\,]+)\s*)/i)
		{
			$h2 = substr($h2, length($1));
			my $key = $2;
			my $val = $3;

			$val =~ s/(^"|"$)//g if ($val =~ /^".*"$/);
			$val =~ s/(^'|'$)//g if ($val =~ /^'.*'$/ && $3 !~ /^".*"$/);

			my $Param = Swignition::RDFModel::BlankNode->new($this->model);
			my $t = $this->graph($gname)->quick_rrr($Param, $rdftype, $nshttp.'Param');
			$this->graph->add_triple($t);

			$t = $this->graph($gname)->quick_rrl($Param, $nshttp.'paramName', $key);
			$this->graph->add_triple($t);

			$t = $this->graph($gname)->quick_rrl($Param, $nshttp.'paramValue', $val);
			$this->graph->add_triple($t);

			$ParamList->add_node($Param);
			
			if (lc($key) eq 'rel')
			{
				$val =~ s/(^\s+)|(\s+$)//g;
				$val =~ s/\s+/ /g;
				
				my @rels = split / /, $val;
				foreach my $rel (@rels)
				{
					$t = $this->graph($gname)->quick_rrr($this->uri, relationship($rel), $uri);
					$this->graph->add_triple($t);

					$this->{Profiles}->{$uri} = 1
						if (lc($rel) eq 'profile');
				}
			}

			elsif (lc($key) eq 'rev')
			{
				$val =~ s/(^\s+)|(\s+$)//g;
				$val =~ s/\s+/ /g;
				
				my @rels = split / /, $val;
				foreach my $rel (@rels)
				{
					$t = $this->graph($gname)->quick_rrr($uri, relationship($rel), $this->uri);
					$this->graph->add_triple($t);
				}
			}
		}
	}

	return $Header;
}

1;
